<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
    
  <meta name="description" content="杰克小麻雀的博客" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    Python 相关文件常见的后缀名详解 |  半亩方塘
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  

</head>

</html>
<body>
  <div id="app">
    
      
      <canvas width="1777" height="841"
        style="position: fixed; left: 0px; top: 0px; z-index: 99999; pointer-events: none;"></canvas>
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-Python 相关文件常见的后缀名详解"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  Python 相关文件常见的后缀名详解
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/2021/05/02/Python%20%E7%9B%B8%E5%85%B3%E6%96%87%E4%BB%B6%E5%B8%B8%E8%A7%81%E7%9A%84%E5%90%8E%E7%BC%80%E5%90%8D%E8%AF%A6%E8%A7%A3/" class="article-date">
  <time datetime="2021-05-03T03:08:18.000Z" itemprop="datePublished">2021-05-02</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/Python/">Python</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">2.9k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">11 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p>常见的 Python 文件后缀有：<code>py </code>、<code>pyc</code> 、<code>pyo</code>、 <code>pyi</code>、<code>pyw</code>、 <code>pyd </code>、 <code>pyx</code> 等。</p>
<p>本文只介绍相对常见的一些后缀名，至于一些特别冷门的文件格式，例如一些文章提到的<code>pyz</code>、<code>pywz</code>、<code>rpy</code>、<code>pyde</code>、<code>pyp</code>、 <code>pyt</code>等，并没有进行研究。因为这些扩展名资料很少，网上搜到的文章似乎都是同一个出处，只是简单提了一句，说了等于没说。</p>
<h3 id="py"><a href="#py" class="headerlink" title="py"></a>py</h3><p>最常见的 Python 源代码文件。</p>
<p>实际上如果用 <code>python + 文件</code> 的方式运行代码，只要文件内容相同，后缀名是不重要的，也就是说下面的运行结果都是等价的：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">python test.py</span><br><span class="line">python test.txt</span><br><span class="line">python test</span><br></pre></td></tr></table></figure>
<h3 id="pyc"><a href="#pyc" class="headerlink" title="pyc"></a>pyc</h3><p>常见的 Python 字节码缓存文件。</p>
<p><code>pyc</code>文件和<code>py</code>文件一样，都可以直接执行，下面的运行结果都是等价的：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python test.py</span><br><span class="line">python test.pyc</span><br></pre></td></tr></table></figure>
<h5 id="作用一：提升加载性能"><a href="#作用一：提升加载性能" class="headerlink" title="作用一：提升加载性能"></a>作用一：提升加载性能</h5><p>我们知道 Python 代码在执行时，会先由 Python 解析器翻译成 PyCodeObject 对象，俗称字节码 (Byte code)，然后交给 Python 解释器来执行字节码。</p>
<p>上述过程中翻译后的字节码是保存在内存中，程序运行结束就没了，而代码没有修改的情况下，每次生成的字节码是一样的，所以每次跑程序都再走一遍翻译字节码的过程有点浪费性能。因此为了提高加载效率，Python 在程序执行结束后会把每个文件的字节码写入到硬盘中保存为 <code>xxx.pyc</code> 文件，这样下一次再执行这个程序时先在目录下找有没有<code>xxx.pyc</code> 文件，如果有这个对应文件且修改时间和<code>xxx.py</code> 文件的修改时间一样，就不用再执行翻译成字节码的过程，直接读取<code>xxx.pyc</code> 文件执行。其实缓存<code>pyc</code> 文件的方式对性能的提升很微小，只有项目文件非常多的时候才能看到显著提升。</p>
<p>默认情况下，我们发现并不是所有的<code>py</code> 文件都会自动生成<code>pyc</code> 文件，只有被其他文件 import 过的文件才会生成对应的<code>pyc</code> 文件。可能 Python 认为被 import 的文件重复使用的概率比较高，而主文件一般只需要加载一次。</p>
<p>简单做个实验可以验证，新建两个 Python 文件<code>hello.py</code>和<code>import.py</code>，内容如下：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># hello.py</span></span><br><span class="line">print(<span class="string">&quot;hello&quot;</span>)</span><br></pre></td></tr></table></figure>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># import.py</span></span><br><span class="line">impot hello</span><br></pre></td></tr></table></figure>
<p>直接运行 <code>python hello.py</code>，并没有生成<code>pyc</code> 文件，而运行<code>python import.py</code>，在当前目录下生成了<code>hello.py</code>对应的<code>pyc</code> 文件。</p>
<p>这里 Python2 和 Python3 有些不同， Python2 是直接在当前目录下生成同名 <code>pyc</code> 文件，Python3 是在当前目录下创建了<code>__pycache__</code>文件夹，然后在文件夹内创建了一个包含 Python 版本信息的<code>xxx.cpython-37.pyc</code> 文件。</p>
<p>Python2</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/2021050217225593.png" alt="2021050217225593"></p>
<p>Python3</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172327565.png" alt="20210502172327565"></p>
<h5 id="作用二：隐藏源代码"><a href="#作用二：隐藏源代码" class="headerlink" title="作用二：隐藏源代码"></a>作用二：隐藏源代码</h5><p><code>pyc</code>格式是给解释器看的二进制文件，直接用编辑器打开看上去是乱码，所以将 Python 代码先编译成<code>pyc</code>文件再交付给别人使用，一定程度上实现隐藏源代码的效果。</p>
<p>默认情况下，主文件不会生成<code>pyc</code>文件，可以通过 Python 自带的<code>py_compile </code>或<code>compileall </code> 库，手动将所有<code>py</code>文件”编译”成<code>pyc</code>文件。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python -m py_compile *.py</span><br><span class="line">python -m compileall *.py</span><br></pre></td></tr></table></figure>
<p>Python2</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172344295.png" alt="20210502172344295"></p>
<p>Python3</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172352924.png" alt="20210502172352924"></p>
<h5 id="反编译-pyc"><a href="#反编译-pyc" class="headerlink" title="反编译 pyc"></a>反编译 pyc</h5><p>前面说了，是“一定程度上实现隐藏源代码的效果”，其实可以通过反编译<code>pyc</code>文件来获得<code>py</code>源码，而且反编译的难度并不大。</p>
<p><code>uncompyle6</code>是一个专门用于将<code>pyc</code>反编译为<code>py</code>源码的第三方库，安装方式：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install uncompyle6</span><br></pre></td></tr></table></figure>
<p>执行下面命令可以将刚才生成的<code>pyc</code>反编译为<code>py</code>文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uncompyle6 -o . *.pyc</span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172413998.png" alt="20210502172413998"></p>
<p>打开生成的文件<code>hello.cpython-37.py</code>和<code>import.cpython-37.py</code>，可以看到和之前的<code>py</code>代码内容一模一样，不过多了一些 Python 的版本信息。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502173823484.png" alt="20210502173823484"></p>
<p> 魔高一尺，道高一丈，有反编译技术就有防止反编译技术，更多了解参见这篇文章：<a target="_blank" rel="noopener" href="https://blog.csdn.net/ir0nf1st/article/details/61650984">通过字节码混淆来保护Python代码</a>。</p>
<h3 id="pyo"><a href="#pyo" class="headerlink" title="pyo"></a>pyo</h3><p>优化后的 Python 字节码缓存文件。</p>
<p><code>pyo</code>文件的作用和<code>pyc</code>文件没啥区别，唯一的优化就是去掉了断言语句，即<code>assert</code>语句。官方文档描述：</p>
<blockquote>
<p>When the Python interpreter is invoked with the -O flag, optimized code is generated and stored in .pyo files. The optimizer currently doesn’t help much; it only removes assert statements. When -O is used, all bytecode is optimized; .pyc files are ignored and .py files are compiled to optimized bytecode.</p>
</blockquote>
<p>同样可以利用<code>py_compile </code>或<code>compileall </code> 库将上面示例的两个文件编译成<code>pyo</code>文件，只是多加一个参数<code>-O</code>，运行结果也没有任何变化：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python -O -m py_compile *.py</span><br><span class="line">python -O -m compileall *.py</span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172534260.png" alt="20210502172534260"></p>
<p>从 Python3.5 开始，Python 只使用 <code>pyc</code> 而不再使用<code>pyo</code>，所以下面命令也无法生成 <code>pyo</code>文件，生成的依然是 <code>pyc</code> 文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python3 -O -m py_compile *.py</span><br><span class="line">python3 -O -m compileall *.py</span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/202105021725479.png" alt="202105021725479"></p>
<h3 id="pyi"><a href="#pyi" class="headerlink" title="pyi"></a>pyi</h3><p>Python 的存根文件，用于代码检查时的类型提示。</p>
<p><code>pyi</code>文件是<code>PEP484</code>提案规定的一种用于 Python 代码类型提示（Type Hints）的文件。<code>PEP</code>即<code>Python Enhancement Proposals</code>，是经过 Python 社区核心开发者讨论并一致同意后，对外发布的一些正式规范文档，例如我们常说的Python之禅(<code>PEP20</code>)，代码风格 PEP8 格式化(<code>PEP8</code>)，将 print 改为函数(<code>PEP3105</code>)等，关于<code>PEP</code>的更多了解见这篇文章：<a target="_blank" rel="noopener" href="https://www.jiqizhixin.com/articles/2018-11-09-4">学习Python，怎能不懂点PEP呢?</a>。</p>
<p>常用的 IDE 都会有类型检查提示功能，比如在 PyCharm 中，当我们给一个函数传入一个错误的类型时会给出对应的提示，这其实不是 IDE 的特殊开发的功能，它只是集成了<code>PEP484</code>的规定，利用了已经预先生成好的 <code>pyi</code>文件。</p>
<p>举个例子，<code>os.makedirs</code>是标准库中用于创建文件夹路径的函数，它的入参应该是一个字符串类型，如果传入一个 int 类型，IDE 会立刻给出提示。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172622846.png" alt="20210502172622846"></p>
<p>按住<code>ctrl</code>点进去，进入到 os 模块定义<code>os.makedirs</code>的地方，发现前面有个<code>*</code>号，鼠标放上去会提示<code>Has stub item in __init__.pyi</code>。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172637274.png" alt="20210502172637274"></p>
<p>点击<code>*</code>号就会跳到对应的<code>__init__.pyi</code>文件，这个文件里按照<code>PEP484</code>规定，为<code>os</code>模块每个函数都定义了对应的类型检查规则。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172648395.png" alt="20210502172648395"></p>
<p>关于<code>pyi</code>文件的定义规则以及自己如何生成，详见官方文档：<a target="_blank" rel="noopener" href="https://www.python.org/dev/peps/pep-0484/">PEP 484 – Type Hints</a></p>
<h3 id="pyw"><a href="#pyw" class="headerlink" title="pyw"></a>pyw</h3><p>一种 Python 源代码文件，一般只存在于 Windows 系统。</p>
<p><code>pyw</code>文件和<code>py</code>文件除了后缀名不一样之外没有任何区别，两者都是 Python 源码文件，前面 <code>py</code>那一节说过“如果用 <code>python + 文件</code> 的方式运行代码，只要文件内容相同，后缀名是不重要的”，这一点在 Windows 系统和 Linux 系统都是一样的。</p>
<p>Windows 系统，新建两个内容相同的 Python 文件<code>hello.py</code>和<code>hello.pyw</code>，用<code>python + 文件</code> 的方式运行，结果一样：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># hello.py</span></span><br><span class="line">print(<span class="string">&quot;hello&quot;</span>)</span><br></pre></td></tr></table></figure>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># hello.pyw</span></span><br><span class="line">print(<span class="string">&quot;hello&quot;</span>)</span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/2021050217270625.png" alt="2021050217270625"></p>
<p>那为什么还要有<code>pyw</code>文件呢？</p>
<p>在Windows 系统上双击文件时，系统会根据文件扩展名来调用关联的<code>exe</code>程序来运行这个文件，打开 Python 安装目录，可以看到有<code>python.exe</code>和<code>pythonw.exe</code>两个<code>exe</code>，其中<code>python.exe</code>关联了<code>py</code>文件，<code>pythonw.exe</code>关联了<code>pyw</code>文件。跟 <code>python.exe</code> 相比，<code>pythonw.exe </code>运行时不会弹出控制台窗口， stdout 、stderr 和 stdin 都无效，所以像 print 这种把内容输出到 stdout 的操作就不会有打印结果（cmd 窗口都没有了也没有地方显示了）。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yushuaige/myblog@master/img/20210502172716282.png" alt="20210502172716282"></p>
<p>所以在用 Python 开发 GUI 程序时，如果不想让程序运行的时候弹出一个黑乎乎的 cmd 框，就可以将源码文件后缀名改为<code>pyw</code>格式。但是我感觉这个<code>pww</code>格式用处并不大，实际使用很少有人双击<code>py</code>或者<code>pyw</code>文件来运行 Python 代码。我之前曾用<code>tkinter</code>开发过带 Windows 界面的 Python 程序，当时是通过双击 <code>bat</code>脚本启动 Python 脚本同时关闭 cmd 界面框，来避免弹出黑框框的。</p>
<h3 id="pyd"><a href="#pyd" class="headerlink" title="pyd"></a>pyd</h3><p>Python 可直接调用的 C 语言动态链接库文件，一般只存在于 Windows 系统。</p>
<p>Python 是一种胶水语言，我们可以将对速度要求比较高的那一部分代码使用 C 语言编写，编译成动态链接库文件，再通过 Python 来调用。一般来说，在 Linux 上是 <code>so</code>文件，在 Windows 系统上是<code>DLL</code>文件。</p>
<p>例如有一个 C 语言编写的  Windows 动态链接库 <code>test_lib.dll</code>，编译前的代码如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sum</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>我们可以在 Python 代码中通过下面的方式来调用</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># test_lib.dll 放在当前目录下</span></span><br><span class="line"><span class="keyword">import</span> ctypes</span><br><span class="line"><span class="keyword">from</span> ctypes <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line">test_lib = ctypes.windll.LoadLibrary(<span class="string">&quot;test_lib.dll&quot;</span>)</span><br><span class="line">a = ctypes.c_int(<span class="number">1</span>)</span><br><span class="line">b = ctypes.c_int(<span class="number">2</span>)</span><br><span class="line">out = test_lib.<span class="built_in">sum</span>(a, b)</span><br><span class="line">print(out) <span class="comment"># 3</span></span><br></pre></td></tr></table></figure>
<p>在 Windows 系统上，Python 还有一种 <code>pyd</code>格式的动态链接库，上面的调用方式是先通过<code>ctypes.windll.LoadLibrary</code> 方法将动态链接库加载进来，而<code>pyd</code>格式就可以在 Python 代码中直接<code>import</code>进来，类似下面这样：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># test_lib.pyd 放在当前目录下</span></span><br><span class="line"><span class="keyword">import</span> test_lib</span><br><span class="line"></span><br><span class="line">out = test_lib.<span class="built_in">sum</span>(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line">print(out) <span class="comment"># 3</span></span><br></pre></td></tr></table></figure>
<p>关于 <code>pyd</code>文件和<code>dll</code>文件的区别，可参考<a target="_blank" rel="noopener" href="https://docs.python.org/3/faq/windows.html#is-a-pyd-file-the-same-as-a-dll">官方文档的说明</a>：</p>
<blockquote>
<p><strong>Is a <code>*.pyd</code> file the same as a DLL?</strong></p>
<p>Yes, .pyd files are dll’s, but there are a few differences. If you have a DLL named <code>foo.pyd</code>, then it must have a function <code>PyInit_foo()</code>. You can then write Python “import foo”, and Python will search for foo.pyd (as well as foo.py, foo.pyc) and if it finds it, will attempt to call <code>PyInit_foo()</code> to initialize it. You do not link your .exe with foo.lib, as that would cause Windows to require the DLL to be present.</p>
<p>Note that the search path for foo.pyd is PYTHONPATH, not the same as the path that Windows uses to search for foo.dll. Also, foo.pyd need not be present to run your program, whereas if you linked your program with a dll, the dll is required. Of course, foo.pyd is required if you want to say <code>import foo</code>. In a DLL, linkage is declared in the source code with <code>__declspec(dllexport)</code>. In a .pyd, linkage is defined in a list of available functions.</p>
</blockquote>
<p>C 语言代码和 Python 代码都可以通过一定的方法编译成<code>pyd</code>格式的文件，本人并没有实际使用过<code>pyd</code>文件，详细方法可参考下面的文章：</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/pengyancai/article/details/54587955">使用C++创建Pyd文件扩展Python模块</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/kdongyi/article/details/102678595">Python源代码保护(Python文件编译生成pyd/so库文件)</a></p>
<h3 id="pyx"><a href="#pyx" class="headerlink" title="pyx"></a>pyx</h3><p>Cython 源代码文件。</p>
<p>注意是 Cython 不是 CPython。Cython 可以说是一种编程语言， 它结合了Python 的语法和有 C/C++的效率，用 Cython 写完的代码可以很容易转成 C 语言代码，然后又可以再编译成动态链接库(<code>pyd</code>或<code>dll</code>)供 Python 调用，所以 Cython 一般用来编写 Python 的 C 扩展，上面说的 Python 文件编译生成 <code>pyd</code> 文件就是利用 Cython 来实现的 。Cython 的源代码文件一般为<code>pyx</code>后缀。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><table>
<thead>
<tr>
<th>后缀名</th>
<th>作用</th>
</tr>
</thead>
<tbody><tr>
<td>py</td>
<td>最常见的 Python 源代码文件。</td>
</tr>
<tr>
<td>pyc</td>
<td>常见的 Python 字节码缓存文件，可以反编译成 py 文件。</td>
</tr>
<tr>
<td>pyo</td>
<td>另一种 Python 字节码缓存文件，只存在于 Python2 及 Python3.5 之前的版本。</td>
</tr>
<tr>
<td>pyi</td>
<td>Python 的存根文件，常用于 IDE 代码格式检查时的类型提示。</td>
</tr>
<tr>
<td>pyw</td>
<td>另一种 Python 源代码文件，一般只存在于 Windows 系统。</td>
</tr>
<tr>
<td>pyd</td>
<td>一种 Python 可直接调用的 C 语言动态链接库文件，一般只存在于 Windows 系统。</td>
</tr>
<tr>
<td>pyx</td>
<td>Cython 源代码文件，一般用来编写 Python 的 C 扩展。</td>
</tr>
</tbody></table>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://example.com/2021/05/02/Python%20%E7%9B%B8%E5%85%B3%E6%96%87%E4%BB%B6%E5%B8%B8%E8%A7%81%E7%9A%84%E5%90%8E%E7%BC%80%E5%90%8D%E8%AF%A6%E8%A7%A3/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Python/" rel="tag">Python</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyc/" rel="tag">pyc</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyd/" rel="tag">pyd</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyi/" rel="tag">pyi</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyo/" rel="tag">pyo</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyw/" rel="tag">pyw</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/pyx/" rel="tag">pyx</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
    
      <a href="/2021/03/19/%E5%AE%9E%E7%94%A8%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90(%E4%BA%8C)%E2%80%94%E2%80%94%E6%9C%80%E5%BC%BA%E5%A4%A7%E7%9A%84%E6%88%AA%E5%9B%BE%E5%B7%A5%E5%85%B7%20(Snipaste)/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">实用软件推荐(二)——最强大的截图工具 (Snipaste)</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "zy6yBRj9KkWO2XxsT94n1DIW-gzGzoHsz",
    app_key: "auroBE2PQXkQ05CLi30SFv92",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "给我的文章加点评论吧~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
  
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2020-2021
        <i class="ri-heart-fill heart_icon"></i> 杰克小麻雀
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        由 <a href="https://hexo.io" target="_blank">Hexo</a> 强力驱动
        <span class="division">|</span>
        主题 - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/favicon.ico" alt="半亩方塘"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/img/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/img/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->


<script src="/js/clickBoom2.js"></script>


<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


    
  </div>
</body>
<script type="text/javascript">
if(!/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)){
  document.write('<script type="text/javascript" src="/js/FunnyTitle.js"><\/script>');
  document.write('<script type="text/javascript" src="/js/snow.js"><\/script>');
}
</script>
</html>